<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>浅拷贝和深拷贝的区别</title>
</head>
<body>
 <script>
   /*
   1.对于字符串类型，浅拷贝是对值的拷贝，对于对象来说，浅拷贝是对对象地址的复制，并没有开辟出新的栈，
   也就是复制的结果是俩个对象指向同一个地址，修改其中一个对象的属性，则另一个对象的属性也会改变，
   而深拷贝则会开辟新的栈，俩个对象对应俩个不同的地址，修改一个对象的属性，不会改变另一个对象的属性
   2.js中数据类型有俩种，分别是基本数据类型和引用数据类型，基本数据类型存放在栈中，我们可以通过值的形式去访问
   后者则是存放在堆和栈中，我们不能直接操作对象的堆内存空间，只能按照引用进行访问，即只能访问栈中的“地址”
   这个地址指向存储在堆中的对象
   */
   var obj = {
     name: 'ysy',
     age: '18',
     friends: ['Kate', 'Bob', 'Mike'],
     hobby: {
       hobby1: 'smoking',
       hobby2: 'LOL'
     }
   }
   function copy (obj1) {
     var obj2 = {}
     for (var key in obj1) {
       obj2[key] = obj1[key]
     }
     return obj2
   }
   var result = copy(obj)
   // result 是对obj的浅拷贝，obj一旦改变，result就会改变，反之亦然
   console.log(result.friends)
   result.friends[0] = 'swift'
   result.age = '19'
   console.log('改变result后的obj', obj)
   // 可以看到 obj的age属性没发生变化，因为是基本数据类型，但是friends数组里面
   // 'Kate',变成了'swift',引用数据类型却发生了变化，说明俩者共用同一个堆地址，但是栈地址却不一样

  // 以上代码可以将obj的值完全拷贝给obj2，看起来确实没有问题，但是一旦修改了原始对象或者拷贝对象的引用类型的属性值，
  //  另一个对象的属性值也会发生相应的改变，很明显这并不是我们想要的。那么为什么修改基本类型的属性值并没有产生影响呢？
  //  那就要从浅拷贝原理说起了，其实浅拷贝只是拷贝一层，对于基本数据类型来说，拷贝的是值，而深层次对象级别的则是拷贝引用，
  //  也就是平常说的地址。既然拷贝的对象与原始对象指向的地址相同，那么二者便会相互影响。


  // ES6中对象新增了一个assign方法，可以迅速实现浅拷贝。这个方法也存在着引用拷贝相互影响的问题
  var obj3 = Object.assign(obj)
  console.log('obj3', obj3)
  console.log('assign方法的浅拷贝', obj3.friends) // ["swift", "Bob", "Mike"]


  /**
   * 在拷贝完成后，我们希望两个对象之间互不影响，也就是说改变任一对象的属性，另一个对象都不会发生改变。那么怎样实现深拷贝呢？
   * 这里介绍两种方法，一种是通过JSON来实现，另一种是运用递归来解决
   * 1.借用JSON的属性可以先用JSON.stringify把对象转成字符串，再用JSON.parse把字符串转成新的对象。
   * 当我们改变原始对象的属性值时，拷贝对象的属性并不会发生变化，但是这种方法存在一个弊端，
   * 我们无法拷贝原始对象的函数，因为函数是无法转成字符串的。
  */
 function deepCopy(obj1) {
   var copyObj = JSON.parse(JSON.stringify(obj1))
   return copyObj
 }
 var result = deepCopy(obj)
 console.log('JSON深拷贝', result.friends) // ["swift", "Bob", "Mike"]
 obj.friends.push('Cherry')
 console.log('改变obj后的result.friends', result.friends) // ["swift", "Bob", "Mike"]
 console.log('改变obj后的obj.friends', obj.friends) // ["swift", "Bob", "Mike", "Cherry"]
 // 可以看到。俩者是独立的！终极解决方案请看02
 </script>
</body>
</html>